﻿#ifndef YCTOOLKIT_UTIL_FILESYSTEM_H_ // 为清晰起见重命名头文件保护
#define YCTOOLKIT_UTIL_FILESYSTEM_H_

#include <string>
#include <filesystem>
#include <fstream>
#include <functional>
#include <system_error>
#include <optional>
#include <vector>
#include <sstream>      // 用于load_file

// 为方便起见的命名空间别名
namespace fs = std::filesystem;

namespace toolkit {

class FileSystem {
public:
    FileSystem() = delete; // 静态类，不允许实例化
    ~FileSystem() = delete;

    /**
     * @brief 创建目录及其所需的所有父目录。
     * @param path 要创建的目录路径。
     * @return 如果目录被创建或已经存在则返回true，出错则返回false。
     */
    static bool createDir(const fs::path &path);

    /**
     * @brief 创建空文件，包括必要的父目录。
     *        如果文件已存在，其内容将被丢弃。
     * @param path 要创建的文件路径。
     * @return 如果文件创建成功则返回true，否则返回false。
     */
    static bool createFile(const fs::path &path);

    /**
     * @brief 检查给定路径是否指向目录。
     * @param path 要检查的路径。
     * @return 如果是目录则返回true，否则返回false（包括不存在的情况）。
     */
    static bool isDir(const fs::path &path);

    /**
     * @brief 检查给定路径的文件名是否为"."或".."。
     * @param path 要检查的路径。
     * @return 如果文件名组件是"."或".."则返回true，否则返回false。
     */
    static bool isSpecialDir(const fs::path &path);

    /**
     * @brief 删除文件或空目录。
     *        要删除非空目录，请使用remove_path_recursive。
     * @param path 要删除的路径。
     * @return 成功删除则返回true，否则返回false（例如，路径未找到、权限错误、目录非空）。
     */
    static bool remove(const fs::path &path);

    /**
     * @brief 递归删除文件或目录。
     *        谨慎使用，尤其是对于目录。
     * @param path 要递归删除的路径。
     * @return 删除的文件/目录数量，或在出错时返回static_cast<uintmax_t>(-1)。
               如果路径不存在则返回0。
     */
    static std::uintmax_t removePathRecursive(const fs::path &path);

    /**
     * @brief 检查路径是否存在（可以是文件、目录、符号链接等）。
     * @param path 要检查的路径。
     * @return 如果路径存在则返回true，否则返回false。
     */
    static bool exists(const fs::path &path);

    /**
     * @brief 将整个文件内容加载到字符串中。
     * @param path 要加载的文件路径。
     * @return 如果成功则返回包含文件内容的optional，否则返回std::nullopt。
     */
    static std::optional<std::string> loadFile(const fs::path &path);

    /**
     * @brief 将字符串数据保存到文件，必要时创建父目录。
     *        如果文件存在，则覆盖它。
     * @param data 要保存的字符串数据。
     * @param path 文件应保存的路径。
     * @return 如果保存成功则返回true，否则返回false。
     */
    static bool saveFile(const std::string &data, const fs::path &path);

    /**
     * @brief 获取给定路径的父目录路径。
     * @param path 输入路径。
     * @return 父目录的路径。如果没有父目录存在（例如，对于根目录或相对路径如"file.txt"），则返回空路径。
     */
    static fs::path parentDir(const fs::path &path);

    /**
     * @brief 计算绝对路径，解析"."和".."。
     *        使用weakly_canonical解析现有部分并规范化其余部分。
     * @param path 输入路径（可以是相对或绝对路径）。
     * @param base_path 用于解析相对路径的基础路径（默认为当前工作目录）。
     * @return 绝对的、规范化的路径，或在出错时返回空路径。
     *         注意：原始的'can_access_parent'逻辑不是标准的，此处省略。
     *               文件系统权限应处理访问控制。
     */
    static fs::path absolutePath(const fs::path &path, const fs::path &base_path = fs::current_path());

    /**
     * @brief 扫描目录，可选择递归，并为每个条目调用回调。
     * @param path 要扫描的目录路径。
     * @param cb 回调函数：`bool callback(const fs::path& entry_path, bool is_directory)`
     *           - `entry_path`：发现的文件或目录的完整路径。
     *           - `is_directory`：如果条目是目录则为true。
     *           - 从回调返回`true`继续扫描，返回`false`停止。
     * @param recursive 如果为true，则进入子目录。
     * @param show_hidden 如果为false，则跳过以'.'开头的条目（隐藏文件/目录的常见约定）。
     */
    static void scanDir(const fs::path &path,
                               const std::function<bool(const fs::path &entry_path, bool is_directory)> &cb,
                               bool recursive = false,
                               bool show_hidden = false);

    /**
     * @brief 获取常规文件的大小。
     * @param path 文件的路径。
     * @return 如果成功则返回包含文件大小（以字节为单位）的optional，否则返回std::nullopt
     *         （例如，路径不存在、不是常规文件或权限错误）。
     */
    static std::optional<std::uintmax_t> fileSize(const fs::path &path);

    /**
     * @brief 尝试删除空目录。
     *        不删除非空目录。不向上递归。
     * @param dir_path 要删除的目录路径。
     * @return 如果目录为空且成功删除则返回true，否则返回false。
     */
    static bool removeEmptyDirectory(const fs::path &dir_path);

    /**
     * @brief 尝试删除空目录并递归删除空的父目录。
     * @param dir_path 要检查并删除（如果为空）的初始目录路径。
     */
    static void removeEmptyDirectoriesRecursive(fs::path dir_path);

}; // class FileSystem

} // namespace toolkit

#endif // YCTOOLKIT_UTIL_FILESYSTEM_H_
